package kr.salebeans.cm.process.customer.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import kr.salebeans.cm.customer.CustomerListDto;
import kr.salebeans.cm.customer.CustomerListRespDto;
import kr.salebeans.cm.customer.CustomerRegisterDto;
import kr.salebeans.cm.customer.CustomerRegisterReqDto;
import kr.salebeans.cm.customer.CustomerRegisterRespDto;
import kr.salebeans.cm.customer.search.CustomerSearchCond;
import kr.salebeans.cm.customer.search.CustomerSearchCond.CustomerSearchType;
import kr.salebeans.cm.domain.common.DataHandling;
import kr.salebeans.cm.domain.customer.Customer;
import kr.salebeans.cm.domain.point.CustomerPoint;
import kr.salebeans.cm.domain.point.PointClsType;
import kr.salebeans.cm.process.customer.CustomerProcess;
import kr.salebeans.cm.provider.customer.CustomerProvider;
import kr.salebeans.cm.provider.point.CustomerPointProvider;
import kr.salebeans.cm.util.DateUtils;
import kr.salebeans.cm.util.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;

public class CustomerProcessImpl implements CustomerProcess {

    /** 고객서비스 */
    @Autowired
    private CustomerProvider customerProvider;

    /** 고객포인트 서비스 */
    @Autowired
    private CustomerPointProvider customerPointProvider;

    public void setCustomerProvider(CustomerProvider customerProvider) {
        this.customerProvider = customerProvider;
    }

    public void setCustomerPointProvider(CustomerPointProvider customerPointProvider) {
        this.customerPointProvider = customerPointProvider;
    }

    /* (non-Javadoc)
     * @see kr.salebeans.cm.process.customer.CustomerProcess#saveCustomer(kr.salebeans.cm.customer.CustomerRegisterReqDto)
     */
    @Override
    public CustomerRegisterRespDto saveCustomer(CustomerRegisterReqDto reqParam) {
        if (reqParam == null || reqParam.getCustomer() == null) {
            throw new RuntimeException("등록할 고객정보가 입력되지 않습니다.");
        }
        CustomerRegisterDto customer = reqParam.getCustomer();
        if (customer.getShopId() != null && customer.getCustomerName().isEmpty()) {
            throw new RuntimeException("샵ID가  입력되지 않았습니다.");
        }
        if (customer.getCustomerName() != null && customer.getCustomerName().isEmpty()) {
            throw new RuntimeException("고객명이 입력되지 않았습니다.");
        }
        if (customer.getGender() == null) {
            throw new RuntimeException("성별이 입력되지 않았습니다.");
        }
        CustomerRegisterDto res = null;
        if (customer.getCustomerId() > 0) {
            res = this.modifyCustomer(customer); // 수정
        }
        else {
            res = this.registerCustomer(customer); // 저장
        }
        CustomerRegisterRespDto respDto = new CustomerRegisterRespDto();
        respDto.setCustomer(res);
        return respDto;
    }

    /**
     *======================================================
     * @method  : CustomerProcessImpl - registerCustomer 
     * @author  : bgkang
     * @since   : 2012. 11. 10.
     * @return  : CustomerRegisterDto
     * @param reqParam
     * @return
     * @note    : 고객저장
     *======================================================
     */
    private CustomerRegisterDto registerCustomer(CustomerRegisterDto reqParam) {
        // #1. 고객도매인 컨버팅
        Customer customer = CustomerConverter.makeCustomer(null, reqParam);
        // #2. 고객저장
        customer = this.customerProvider.createCustomer(customer);
        // #3. 고객포인트 저장
        if (reqParam.getPoint() > 0) {
            CustomerPoint customerPoint = new CustomerPoint();
            customerPoint.setCustomerId(customer.getId());
            customerPoint.setPoint(reqParam.getPoint());
            customerPoint.setPointCls(PointClsType.PLUS);
            customerPoint.setRegisterDateTime(DateUtils.getCurrentBaseDateString());
            customerPoint.setRemark("신규고객등록시 포인트 등록");
            this.customerPointProvider.createCustomerPoint(customerPoint);
        }

        CustomerRegisterDto resDto = CustomerConverter.makeCustomerRegisterDto(customer);
        resDto.setPoint(this.customerPointProvider.getCurrentCusotemrPoint(reqParam.getCustomerId()));
        return resDto;
    }

    /**
     *======================================================
     * @method  : CustomerProcessImpl - modifyCustomer 
     * @author  : bgkang
     * @since   : 2012. 11. 10.
     * @return  : CustomerRegisterDto
     * @param reqParam
     * @return
     * @note    : 고객수정
     *======================================================
     */
    private CustomerRegisterDto modifyCustomer(CustomerRegisterDto reqParam) {
        if (reqParam.getCustomerId() <= 0) {
            throw new RuntimeException("고객아이디가 입력되지 않았습니다.");
        }
        Customer savedCustomer = this.customerProvider.retrieveCustomer(reqParam.getCustomerId());
        if (savedCustomer == null) {
            throw new RuntimeException("고객아이디 " + reqParam.getCustomerId() + "에 해당하는 고객없음");
        }
        // #2. 고객포인트 저장
        long currentPoint = this.customerPointProvider.getCurrentCusotemrPoint(reqParam.getCustomerId());
        if (currentPoint != reqParam.getPoint()) {
            PointClsType type = null;
            long point = 0;
            String remark = "사용자가 직접 수정 [%1s] 원 %2s] ";
            if (currentPoint > reqParam.getPoint()) {
                type = PointClsType.MINUS;
                point = currentPoint - reqParam.getPoint();
                remark = String.format(remark, point, "차감");
            }
            else {
                type = PointClsType.PLUS;
                point = reqParam.getPoint() - currentPoint;
                remark = String.format(remark, point, "증감");
            }
            CustomerPoint customerPoint = new CustomerPoint();
            customerPoint.setCustomerId(savedCustomer.getId());
            customerPoint.setPoint(point);
            customerPoint.setPointCls(type);
            customerPoint.setRegisterDateTime(DateUtils.getCurrentBaseDateString());
            customerPoint.setRemark(remark);
            this.customerPointProvider.createCustomerPoint(customerPoint);
        }
        // #3. 고객수정
        savedCustomer = CustomerConverter.makeCustomer(savedCustomer, reqParam);
        DataHandling handling = savedCustomer.getHandling();
        handling.setUpdateDateTime(DateUtils.getCurrentBaseDateString());
        this.customerProvider.updateCustomer(savedCustomer);

        CustomerRegisterDto resDto = CustomerConverter.makeCustomerRegisterDto(savedCustomer);
        resDto.setPoint(this.customerPointProvider.getCurrentCusotemrPoint(reqParam.getCustomerId()));
        return resDto;
    }

    /* (non-Javadoc)
     * @see kr.salebeans.cm.process.customer.CustomerProcess#getCustomer(long)
     */
    @Override
    public CustomerRegisterRespDto getCustomer(long customerId) {
        if (customerId == 0) throw new RuntimeException("고객아이디가 입력되지 않았습니다.");

        Customer customer = customerProvider.retrieveCustomer(customerId);
        if (customer == null) throw new RuntimeException("등록된 고객이 아닙니다.");

        CustomerRegisterDto resDto = CustomerConverter.makeCustomerRegisterDto(customer);
        resDto.setPoint(this.customerPointProvider.getCurrentCusotemrPoint(customerId));
        CustomerRegisterRespDto respDto = new CustomerRegisterRespDto();
        respDto.setCustomer(resDto);
        return respDto;
    }

    @Override
    public CustomerListRespDto findCustomerList(CustomerSearchCond searchCond) {
        if (searchCond == null) throw new RuntimeException("고객 조회조건이 입력되지 않았습니다.");
        if (StringUtils.isBlank(searchCond.getShopId())) throw new RuntimeException("샵아이디가 입력되지 않았습니다.");
        if (searchCond.getSearchType() == null) {
            searchCond.setSearchType(CustomerSearchType.ALL);
        }

        CustomerListRespDto respDto = new CustomerListRespDto();
        respDto.setFistIndex(searchCond.getFirstIndex());
        respDto.setMaxIndex(searchCond.getMaxIndex());

        // #1. 고객목록조회
        List<Customer> customerList = this.customerProvider.retrieveCustomerList(searchCond);
        if (customerList == null || customerList.isEmpty()) {
            return respDto;
        }

        // #2. 고객포인트조회
        List<Long> customerIds = new ArrayList<Long>(customerList.size() + 1);
        for (Customer customer : customerList) {
            customerIds.add(customer.getId());
        }

        Map<Long, Long> customerPointMap = this.customerPointProvider.retrieveCurrentCustomerListPoint(customerIds);

        // #3. DTO Convert
        List<CustomerListDto> customerListDto = new ArrayList<CustomerListDto>(customerList.size() + 1);
        for (Customer customer : customerList) {
            CustomerListDto customerDto = new CustomerListDto();
            customerDto.setCustomerId(customer.getId());
            customerDto.setCustomerName(customer.getCustomerName());
            customerDto.setGender(customer.getGender());
            if (customer.getContactPoint() != null) {
                customerDto.setTelNo(customer.getContactPoint().makePhoneNo());
                customerDto.setCellPhoneNo(customer.getContactPoint().makeCellPhoneNo());
            }
            if (customerPointMap != null && customerPointMap.get(customer.getId()) != null) {
                customerDto.setPoint(customerPointMap.get(customer.getId()));
            }
            customerListDto.add(customerDto);
        }
        respDto.setCustomerList(customerListDto);

        // #4. 총 고객수 세팅
        respDto.setTotalCustomerCount(this.customerProvider.retrieveTotalCustomerListCount(searchCond));
        return respDto;
    }
}
